# author: HuDaoquan
# contact: 1455523026@qq.com
# datetime:2022/5/2 20:24
# software: PyCharm

"""
文件说明：
"""
import multiprocessing
import threading
from concurrent.futures import ProcessPoolExecutor
import gitlab
import datetime
import json
import os
import json

from gevent.threadpool import ThreadPoolExecutor

ip_token = {
    # '10.39.39.149': 'bzs78Rx4q5szgyxdWtzD',
    '10.39.39.18': 'VJQphpeRXoJQb1yTT-16',
}


class ProjectInfo1(json.JSONEncoder):
    """
      工程信息的结构体
    """
    projectId = None
    thisProjectURL = None
    description = None
    lastActivityAt = None


class MemberDetails(ProjectInfo1, json.JSONEncoder):
    """
      项目成员结构体
    """
    userId = None
    userCnName = None
    userName = None
    userLevel = None
    userExpiryDate = None
    userAccessLevel = None



def get_user_projects(self, userid):
    """
    获取用户所拥有的项目
    :param userid:
    :return:
    """
    projects = self.gl.projects.owned(userid=userid, all=True)
    result_list = []
    for project in projects:
        result_list.append(project.http_url_to_repo)
    return result_list


def get_group_projects(self, groupname):
    """
    获取组内项目！！！！！！！其他博客也有类似方法，实测不能拿到群组内项目，现经过小改动，亲测可满足要求
    :param groupname:
    :return:
    """
    group = self.gl.groups.get(groupname, all=True)
    projects = group.projects.list(all=True)
    return projects


def getContent(self, projectID):
    """
    通过项目id获取文件内容
    :param projectID:
    :return:
    """
    projects = self.gl.projects.get(projectID)
    f = projects.files.get(file_path='指定项目中的文件路径', ref='master')
    content = f.decode()
    # print(content)
    return content.decode('utf-8')


def get_all_group(self):
    """
    获取所有群组
    :return:
    """
    return self.gl.groups.list(all=True)


def get_all_project(self):
    """
    获取所有项目
    :return:
    """
    return self.gl.projects.list(all=True)


def get_all_user(self):
    """
    获取所有项目
    :return:
    """
    return self.gl.users.list(all=True)


def write_all_member_csv(file_path, project_member_list):
    """
      导出所有有效成员为excel
      :param file_path:文件路径
      :param project_member_list: 项目成员信息
      :param extra:额外数据列
      :return:
      """
    if file_path.endswith("/"):
        if not os.path.exists(file_path):
            os.makedirs(file_path)
    else:
        folder_path = file_path[0:file_path.rfind('/') + 1]
        if not os.path.exists(folder_path):
            os.makedirs(folder_path)
    print("开始写文件---------------------------------")
    with open(file_path, 'w') as out:
        title = '项目id,项目描述,项目路径,项目最后活跃时间,用户id,用户中文名,用户账号,用户权限,权限有效期'
        out.write(title + "\n")
        for csvCow in project_member_list:
            rowText = '%s,%s,%s,%s,%s,%s,%s,%s,%s' % \
                      (csvCow.projectId, csvCow.description, csvCow.thisProjectURL, csvCow.lastActivityAt,
                       csvCow.userId, csvCow.userCnName, csvCow.userName, csvCow.userLevel, csvCow.userExpiryDate)
            out.write(rowText + '\n')
        out.close()


def get_member(project_one):
    """
    传入一个项目对象，输出其所有成员信息
    """
    description = project_one.description
    if description is not None:
        description = description.replace("\r\n", "。")
    members = project_one.members.list(all=True)
    m_list = []
    # 标记有效成员是否为空
    flag = 0
    for m in members:
        # 跳过禁用的用户
        if m.state == 'blocked':
            continue
        user_expiry_date = m.expires_at
        flag = 1
        if user_expiry_date is None:
            user_expiry_date = '无期限'
        user_level = m.access_level
        match user_level:
            case 10:
                user_level = 'Guest'
            case 20:
                user_level = 'Reporter'
            case 30:
                user_level = 'Developer'
            case 40:
                user_level = 'Master'
            case 50:
                user_level = 'Owner'
        details = MemberDetails()
        details.projectId = m.project_id
        details.userId = m.id
        details.userCnName = m.name
        details.userName = m.username
        details.userLevel = user_level
        details.userAccessLevel = m.access_level
        details.userExpiryDate = user_expiry_date
        details.thisProjectURL = project_one.http_url_to_repo
        details.description = description
        details.lastActivityAt = project_one.last_activity_at.split(".")[0].replace("T", " ")
        m_list.append(details)
        members_list.append(details)
    # 成员中没有有效成员
    if flag == 0:
        details = MemberDetails()
        details.projectId = project_one.id
        details.userId = "无"
        details.userCnName = "无"
        details.userName = "无"
        details.userLevel = "无"
        details.userAccessLevel = "无"
        details.userExpiryDate = "无"
        details.thisProjectURL = project_one.http_url_to_repo
        details.description = description
        details.lastActivityAt = project_one.last_activity_at.split(".")[0].replace("T", " ")
        m_list.append(details)
        members_list.append(details)
    return m_list

def get_member_master(project_one):
    """
    传入一个项目对象，输出其所有成员信息
    """
    description = project_one.description
    if description is not None:
        description = description.replace("\r\n", "。")
    members = project_one.members.list(all=True)
    m_list = []
    # 标记有效成员是否为空
    flag = 0
    for m in members:
        # 跳过禁用的用户
        if m.state == 'blocked':
            continue
        user_expiry_date = m.expires_at

        if user_expiry_date is None:
            user_expiry_date = '无期限'
        user_level = m.access_level

        match user_level:
            case 40:
                user_level = 'Master'
                flag = 1
                details = MemberDetails()
                details.projectId = m.project_id
                details.userId = m.id
                details.userCnName = m.name
                details.userName = m.username
                details.userLevel = user_level
                details.userAccessLevel = m.access_level
                details.userExpiryDate = user_expiry_date
                details.thisProjectURL = project_one.http_url_to_repo
                details.description = description
                details.lastActivityAt = project_one.last_activity_at.split(".")[0].replace("T", " ")
                m_list.append(details)
                members_list.append(details)
            case 50:
                user_level = 'Owner'
                flag = 1
                details = MemberDetails()
                details.projectId = m.project_id
                details.userId = m.id
                details.userCnName = m.name
                details.userName = m.username
                details.userLevel = user_level
                details.userAccessLevel = m.access_level
                details.userExpiryDate = user_expiry_date
                details.thisProjectURL = project_one.http_url_to_repo
                details.description = description
                details.lastActivityAt = project_one.last_activity_at.split(".")[0].replace("T", " ")
                m_list.append(details)
                members_list.append(details)
    # 成员中没有有效成员
    if flag == 0:
        details = MemberDetails()
        details.projectId = project_one.id
        details.userId = "无"
        details.userCnName = "无"
        details.userName = "无"
        details.userLevel = "无"
        details.userAccessLevel = "无"
        details.userExpiryDate = "无"
        details.thisProjectURL = project_one.http_url_to_repo
        details.description = description
        details.lastActivityAt = project_one.last_activity_at.split(".")[0].replace("T", " ")
        m_list.append(details)
        members_list.append(details)
    return m_list

def page_member(index):
    """
    方法用于
    """
    projects = gl.projects.list(page=index)
    if len(projects) == 0:
        return
    for project in projects:
        # print("页码" + str(index) + "项目id" + str(project.id) + "导出成员，线程：======" + str(threading.current_thread().ident))
        # 导出所有项目成员
        # get_member(project)
        # 导出master权限成员
        get_member_master(project)
    # return page_member_list


def page_member_thread():
    """
    方法用于分页多线程获取所有项目成员信息
    """
    pool = ThreadPoolExecutor(max_workers=16)  # 创建线程池对象,设置线程池大小，建议不超过cpu数*5
    for i in range(1, 100):
        print(str(i) + "分页，线程" + str(threading.current_thread().ident))
        pool.submit(page_member, (i,))
    
    pool.shutdown()  # 线程池被执行完，才会执行主线程的内容。


def write_to_csv_group(file_path, project_member_list):
    """
      工具方法：将结果写入csv，从#final_commit_map参数解析业务数据
      :param file_path:文件路径
      :param project_member_list: 项目成员信息
      :param extra:额外数据列
      :return:
      """
    if file_path.endswith("/"):
        if not os.path.exists(file_path):
            os.makedirs(file_path)
    else:
        folder_path = file_path[0:file_path.rfind('/') + 1]
        if not os.path.exists(folder_path):
            os.makedirs(folder_path)
    print("开始写文件---------------------------------")
    with open(file_path, 'w') as out:
        title = '%s,%s,%s,%s,%s,%s,%s,%s,%s,%s' % (
            "项目id", "项目描述", "项目路径", "父目录id", "用户id", "用户中文名", "用户账号", "用户权限", "权限有效期", "状态")
        out.write(title + "\n")
        for csvCow in project_member_list:
            var = '%s,%s,%s,%s,%s,%s,%s,%s,%s,%s' % (
                csvCow.projectId, csvCow.description, csvCow.thisProjectURL, csvCow.parentId,
                csvCow.userId, csvCow.userCnName, csvCow.userName, csvCow.userLevel, csvCow.userExpiryDate,
                csvCow.State)
            out.write(var + '\n')
        out.close()


def get_group_info():
    """
    方法用于获取所有组信息
    """
    all_groups = gl.groups.list(all=True)
    group_m_list = []
    for group in all_groups:
        description = group.description
        if description is not None:
            description = description.replace("\r\n", "。").replace(",", "，")
        else:
            description = group.name.replace("\r\n", "。")
        
        group_member_list = group.members.list(all=True)
        print(description)
        # 标记有效成员是否为空
        flag = 0
        for m in group_member_list:
            # 跳过禁用的用户
            if m.state == 'blocked':
                continue
            user_expiry_date = m.expires_at
            flag = 1
            if user_expiry_date is None:
                user_expiry_date = '无期限'
            user_level = m.access_level
            match user_level:
                case 10:
                    user_level = 'Guest'
                case 20:
                    user_level = 'Reporter'
                case 30:
                    user_level = 'Developer'
                case 40:
                    user_level = 'Master'
                case 50:
                    user_level = 'Owner'
            details = MemberDetails()
            details.projectId = group.id
            details.parentId = group.parent_id
            details.userId = m.id
            details.userCnName = m.name
            details.userName = m.username
            details.userLevel = user_level
            details.userAccessLevel = m.access_level
            details.userExpiryDate = user_expiry_date
            details.thisProjectURL = group.web_url
            details.description = description
            details.State = m.state
            group_m_list.append(details)
        # 成员中没有有效成员
        if flag == 0:
            details = MemberDetails()
            details.projectId = group.id
            details.parentId = group.parent_id
            details.userId = "无"
            details.userCnName = "无"
            details.userName = "无"
            details.userLevel = "无"
            details.userAccessLevel = "无"
            details.userExpiryDate = "无"
            details.thisProjectURL = group.web_url
            details.description = description
            details.State = "无"
            group_m_list.append(details)
    return group_m_list


if __name__ == '__main__':
    # 当前时间
    start_time = datetime.datetime.now()
    print(start_time)
    # 文件名
    memberFileName = "./dist/member_%s.csv" % ('{:%Y%m%d%H%M%S}'.format(start_time))
    groupFileName = "./dist/group_%s.csv" % ('{:%Y%m%d%H%M%S}'.format(start_time))

    # 存储所有成员信息
    members_list = []
    # 遍历服务器ip和token
    for gitlabAddress, gitlabToken in ip_token.items():
        gl = gitlab.Gitlab('http://' + gitlabAddress, private_token=gitlabToken, api_version='4')
        page_member_thread()
        # #  导出组及成员
        # group_m = get_group_info()
        # write_to_csv_group(groupFileName, group_m)
   # 导出项目成员为csv
    write_all_member_csv(memberFileName, members_list)






    end_time = datetime.datetime.now()
    print(end_time)
    print("耗时（秒）:" + str((end_time - start_time).seconds))
